//using System;
//using System.Collections.Generic;
//using System.Text;
//using System.Drawing;
//using System.IO;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using MapEditor;
using System.Configuration;
using System.IO;

namespace MapEditor
{
    class CC
    {
        public enum CCVersion
        {
            CC3,
            CC5,
            CCM
        }



        public enum TerrainType
        {
            Elevation,
            Terrain
        }

        private static int ConvertLongToInt(byte[] ByteArray, int Position){
            //this uses little endian byte ordering
            int ReturnValue;
            ReturnValue = (int)(ByteArray[Position] + (ByteArray[Position + 1] * 256) + (ByteArray[Position + 2] * 4096) + (ByteArray[Position+3] * 65536));

            return ReturnValue;

        }

        public static Roofs LoadRoofInformation(string FoofFileLocation){
            Roofs myRoofs = new Roofs();
            
            //read in the roof file
            FileInfo fi = new FileInfo(FoofFileLocation);
            FileStream fs = fi.OpenRead();
            int FileSize = (int)fi.Length;
            byte[] ByteArray = new byte[FileSize];
            fs.Read(ByteArray, 0, FileSize);
            fs.Close();


            //get the number of roofs

            int NumberOfRoofs;
            NumberOfRoofs = ConvertLongToInt(ByteArray,4);
            myRoofs.NumberOfRoofs = NumberOfRoofs;

            myRoofs.RoofArray = new Roof[NumberOfRoofs];

            int RoofCounter;

            //loop through each roofpair and get the header information
            for (RoofCounter = 0; RoofCounter < NumberOfRoofs; RoofCounter++)
            {
                int CurrentOffset = 16 + (RoofCounter * 132);

                //roof pair info starts at byte 16, and each one has 132 bytes of info


                //create a new roof in the roof array
                myRoofs.RoofArray[RoofCounter] = new Roof();
                
                //get number of roof images
                int NumberOfRoofImages;
                NumberOfRoofImages = ConvertLongToInt(ByteArray,CurrentOffset);
                myRoofs.RoofArray[RoofCounter].NumberOfRoofImages = NumberOfRoofImages;

                //get number of vertices
                int NumberOfVertices;
                NumberOfVertices = ConvertLongToInt(ByteArray, CurrentOffset + 4);
                myRoofs.RoofArray[RoofCounter].NumberOfVertices = NumberOfVertices;
                myRoofs.RoofArray[RoofCounter].Vertices = new Vertex[12];

                //increment the offset to jump over the imagecount and vertexcount
                CurrentOffset += 8;

                //next loop through the vertex info
                int VertexLooper;
                for (VertexLooper = 0; VertexLooper < NumberOfVertices; VertexLooper++)
                {

                    myRoofs.RoofArray[RoofCounter].Vertices[VertexLooper] = new Vertex();

                    int XCoord, YCoord;

                    XCoord = ConvertLongToInt(ByteArray, CurrentOffset + (VertexLooper * 8));
                    myRoofs.RoofArray[RoofCounter].Vertices[VertexLooper].XCoordinate = XCoord;

                    //Array.Copy(ByteArray, CurrentOffset + 4+(VertexLooper * 8), LongValue, 0, 4);
                    YCoord = ConvertLongToInt(ByteArray, CurrentOffset + 4 + (VertexLooper * 8));
                    myRoofs.RoofArray[RoofCounter].Vertices[VertexLooper].YCoordinate = YCoord;
                }
                //to jump over the vertex data - it is fixed width, 
                //so the unused vertices are also stored
                CurrentOffset += 96;
                
                //get the roof width
                int RoofWidth;
                RoofWidth = ConvertLongToInt(ByteArray, CurrentOffset)/2;

                //get the roof top left x coordinate
                CurrentOffset += 4;
                int RoofTopLeftX;
                RoofTopLeftX = ConvertLongToInt(ByteArray, CurrentOffset);

                //get the roof top left y coordinate
                CurrentOffset += 4;
                int RoofTopLeftY;
                RoofTopLeftY = ConvertLongToInt(ByteArray, CurrentOffset);

                //get the roof bottom right x coordinate
                CurrentOffset += 4;
                int RoofBottomRightX;
                RoofBottomRightX = ConvertLongToInt(ByteArray, CurrentOffset);

                //get the roof bottom right y coordinate
                CurrentOffset += 4;
                int RoofBottomRightY;
                RoofBottomRightY = ConvertLongToInt(ByteArray, CurrentOffset);

                //get the offset of exterior data
                CurrentOffset += 4;
                int ExteriorOffset;
                ExteriorOffset = ConvertLongToInt(ByteArray, CurrentOffset);

                //get the offset of interior data
                CurrentOffset += 4;
                int InteriorOffset;
                InteriorOffset = ConvertLongToInt(ByteArray, CurrentOffset);

                //calc the height and width
                int ImageHeight, ImageWidth;
                ImageHeight = RoofBottomRightY - RoofTopLeftY;
                ImageWidth = RoofBottomRightX - RoofTopLeftX;

                int NumberOfPixels;
                NumberOfPixels = ImageHeight * ImageWidth;
                //get the roof exterior image



                //get the roof interior image





            }

            return myRoofs;
        }


        private static Image ConvertByteArrayToImage(byte[] ByteArray, int ImageWidth, int ImageHeight, int Offset)
        {
            return null;
        }


        public static Image ConvertCCMapToIMage(string CCMapFileLocation)
        {

            //load the cc file
            FileInfo fi = new FileInfo(CCMapFileLocation);
            FileStream fs = fi.OpenRead();
            int FileSize = (int)fi.Length;

            //read the file into a bytearray - adding 2 bytes for the length
            //of a targa header compared to a cc header
            byte[] ByteArray = new byte[FileSize+2];
            fs.Read(ByteArray, 2, FileSize);

            int MapWidth = 0;
            int MapHeight = 0;
            MapWidth = ByteArray[11] * 256 + ByteArray[10];
            MapHeight = ByteArray[15] * 256 + ByteArray[14];
            //save as a temporary file for devIL to load
            string tempFileName = CCMapFileLocation + System.Guid.NewGuid() + ".tga";

            FileStream fso = new FileStream(tempFileName, FileMode.CreateNew);
            // Create the writer for data.
            BinaryWriter w = new BinaryWriter(fso);
            int looper;
            ByteArray[0] = 0;
            ByteArray[1] = 0;
            ByteArray[2] = 2;
            ByteArray[3] = 0;
            ByteArray[4] = 0;
            ByteArray[5] = 0;
            ByteArray[6] = 0;
            ByteArray[7] = 0;
            ByteArray[8] = 0;
            ByteArray[9] = 0;
            ByteArray[10] = 0;
            ByteArray[11] = 0;
            ByteArray[12] = Convert.ToByte(MapWidth % 256); //width 1
            ByteArray[13] = Convert.ToByte(MapWidth / 256);  //width 2
            ByteArray[14] = Convert.ToByte(MapHeight % 256);//height 1
            ByteArray[15] = Convert.ToByte(MapHeight / 256); //height 2
            ByteArray[16] = 16; // bit depth
            ByteArray[17] = 33; //image desc - was 33?

            Image myImage;
            for (looper = 0; looper < FileSize+2; looper++)
            {
                w.Write(ByteArray[looper]);

            }
            w.Close();
            fs.Close();
            //load the generated targa
            myImage = DevIL.DevIL.LoadBitmap(tempFileName);
                        //delete the temporary file
            File.Delete(tempFileName);



            return myImage;

        }
        
        public static Array LoadTerrain(string terrainFileLocation, ref Map myMap, TerrainType Setting)
       {
           string line;
           int counter = 0;
           int TerrainX;
           int TerrainY;
           int mapHeight = myMap.Height;
           int mapWidth = myMap.Width;
           Array MapArray = Array.CreateInstance(typeof(int), mapWidth, mapHeight);

           using (StreamReader sr = new StreamReader(terrainFileLocation))
           {



               while (counter < 8) { sr.ReadLine(); counter++; }

               for (TerrainY = 0; TerrainY < (mapHeight / 40); TerrainY++)

                   {
                       for (TerrainX = 0; TerrainX < (mapWidth / 40); TerrainX++)
                       {
                           if ((line = sr.ReadLine()) != null)
                           {
                               if (line.Substring(0, 1) != "#")  //while not the last line
                               {
                                   //get the position of the first tab
                                   int looperX, looperY;
                                   string tabValue;
                                   int tabCounter = 1;


                                   for (looperX = 0; looperX <= 3; looperX++)
                                   {
                                       for (looperY = 0; looperY <= 3; looperY++)
                                       {
                                           switch (Setting)
                                           {
                                               case TerrainType.Terrain:
                                                   tabValue = GetTabbedValue(line, tabCounter);
                                                   MapArray.SetValue(Convert.ToInt16(tabValue), (TerrainX * 4) + looperX, (TerrainY * 4) + looperY);
                                                   break;
                                               case TerrainType.Elevation :
                                                   tabValue = GetTabbedValue(line, tabCounter + 16);
                                                   MapArray.SetValue(Convert.ToInt16(tabValue), (TerrainX * 4) + looperX, (TerrainY * 4) + looperY);
                                                   break;
                                           }

                                               


                                           tabCounter++;
                                       }
                                       //go through each line and get the terrain values
                                   }

                               }
                           }
                       }
                   }
               
               }

               return MapArray;
       }//LoadTerrain
                
        private static string GetTabbedValue(string textString, int tabPosition)
       {
           //gets the value of text after the tabPosition instance of the tab (0-based)
           //and before the next tab
           int looper;
           int LastPosition = 0;
           string partialLine = textString;
           string ReturnString = "";


           if (tabPosition == 0)
           {
               LastPosition = textString.IndexOf("\t");
               ReturnString = textString.Substring(0, LastPosition);
           }
           else
           {
               for (looper = 0; looper <= tabPosition; looper++)
               {
                   //loop through the string <tabPosition> times
                   // checking the index of tab character in the decreasing substring

                   partialLine = partialLine.Substring(LastPosition);
                   LastPosition = partialLine.IndexOf("\t");
                   ReturnString = partialLine.Substring(0, LastPosition);
                   LastPosition += 1;  //to jump over the tab for the next string
               }
           }


           return ReturnString;

       }//GetTabbedValue

        public static Array LoadTerrainElementsFromFile(string ElementFileLocation)
        {
            TerrainElements myTerrainElements = new TerrainElements();

            //serialisation in
            System.Xml.Serialization.XmlSerializer reader = new System.Xml.Serialization.XmlSerializer(typeof(TerrainElements));
            System.IO.Stream fs = new FileStream(ElementFileLocation, FileMode.Open);
            myTerrainElements = (TerrainElements)reader.Deserialize(fs);
            fs.Close();

            return myTerrainElements.TerrainArray;
        }

        //TODO extend and then remove!
        public static Array CreateTerrainElements(string ElementFileLocation, CCVersion Version)
        {
            string line;
            int counter = 0;
            int ElementIndex = 0;
            //Array ElementArray;
            TerrainElements myTerrainElements = new TerrainElements();




            switch (Version)
            {
                case CC.CCVersion.CC5:
                    Array.Resize(ref myTerrainElements.TerrainArray, 159);
                    break;
                default:
                    //load cc5 elements
                    Array.Resize(ref myTerrainElements.TerrainArray, 159);
                    break;
            }


            using (StreamReader sr = new StreamReader(ElementFileLocation))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    //ignore the first 4 lines
                    if (counter > 3)
                    {
                        //stop when we get to the last line
                        if (line.Substring(0, 1) != "#")
                        {
                            //TODO load an XML description of the elements
                            //pass in the CC text value
                            //to get the corresponding FM terrain description
                            //the XML description will have the FM elements
                            //and their corresponding CC names (if present - will have variants if needed)
                            TerrainElements.Terrain myTerrain;
                            myTerrain = new TerrainElements.Terrain();
                            myTerrain.Name = GetTabbedValue(line, 0);
                            myTerrain.Value = Convert.ToString(ElementIndex);
                            myTerrainElements.TerrainArray.SetValue(myTerrain, ElementIndex);
                            
                            ElementIndex++;
                        }
                    }
                    counter++;
                }
            }
             //test serialization out
            System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(TerrainElements));
            System.IO.Stream fs = new FileStream("c:\\test.xml", FileMode.Create);
            writer.Serialize(fs, myTerrainElements);
            fs.Close();




            return myTerrainElements.TerrainArray;
            }



        }

    }



